import os
import traceback

from PyQt6.QtCore import QRect, QPoint, Qt, pyqtSignal, pyqtBoundSignal
from PyQt6.QtGui import QDropEvent, QMouseEvent, QDragEnterEvent, QPainter, QPen, QColor, QFont, QPixmap
from PyQt6.QtWidgets import QLabel, QSizePolicy, QFileDialog


class ImageLabel(QLabel):
    """自定义标签类，用于显示图片并支持拖拽和选择区域"""
    
    # 定义信号，当选区改变时发射
    selectionChanged = pyqtSignal(object, int, int, int, int, str, str)
    # 定义信号，当图片加载时发射图片尺寸
    imageLoaded = pyqtSignal(int, int)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.pixmap = None  # 图片对象
        self.selection_rect = QRect()  # 选区矩形
        self.start_point = QPoint()  # 鼠标按下时的坐标
        self.end_point = QPoint()  # 鼠标松开时的坐标
        self.drawing = False  # 是否正在绘制选区
        self.scale_factor = 1.0  # 缩放因子

        # 启用拖拽功能
        self.setAcceptDrops(True)
        
        # 启用鼠标跟踪
        self.setMouseTracking(True)

        self.setText("拖拽图片到此处或点击选择图片")
        font = QFont()
        font.setPointSize(10)
        self.setFont(font)
        # 设置样式以提示用户可以拖拽
        self.setStyleSheet("border: 1px solid gray;")
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
        # 设置尺寸策略，使用Preferred而不是Expanding，避免过度扩展
        self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)

        self.setTextFormat(Qt.TextFormat.AutoText)
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
        
        print("ImageLabel initialized")

    def mousePressEvent(self, event: QMouseEvent):
        """处理鼠标按下事件"""
        print(f"mousePressEvent called, button: {event.button()}")
        if event.button() == Qt.MouseButton.LeftButton:
            # 获取焦点确保可以接收后续事件
            self.setFocus()
            # 如果当前没有图片，则触发选择图片操作
            if not self.pixmap:
                print("No pixmap, loading image（没有图片，加载图片）")
                self.load_image()
            elif self.pixmap:
                print("Pixmap exists, starting drawing（图片存在，开始绘制）")
                self.drawing = True
                self.start_point = event.pos()
                self.end_point = event.pos()
                print(f"Start point: {self.start_point}, End point: {self.end_point}")
                self.update()
        # 调用父类方法确保事件被正确处理
        super().mousePressEvent(event)

    def load_image(self):
        """打开文件选择对话框并加载图片"""
        print("load_image called（调用加载图片方法）")
        file_path, _ = QFileDialog.getOpenFileName(
            self, 
            "选择图片文件", 
            "", 
            "Images (*.png *.jpg *.jpeg *.bmp)"
        )
        
        if file_path:
            print(f"Loading image from path: {file_path}（从路径加载图片）")
            self.load_image_from_path(file_path)

    def load_image_from_path(self, file_path):
        """从指定路径加载图片"""
        print(f"load_image_from_path called with path: {file_path}（调用从路径加载图片方法）")
        pixmap = QPixmap(file_path)
        if not pixmap.isNull():
            print("Pixmap loaded successfully（图片加载成功）")
            self.setPixmap(pixmap)
            # 重置选区
            self.selection_rect = QRect()
            self.update()
            
            # 发射图片尺寸变化信号
            print("Emitting image size changed signal")
            self.imageSizeChanged.emit(pixmap.width(), pixmap.height())
        else:
            print("Failed to load pixmap（图片加载失败）")

    def get_scaled_pixmap_rect(self):
        """获取图像在标签中的实际绘制区域"""
        print("get_scaled_pixmap_rect called（获取图像在标签中的实际绘制区域）")
        if not self.pixmap:
            print("No pixmap, returning empty QRect（没有图片，返回空矩形）")
            return QRect()

        # 计算图像在标签中的实际绘制区域（居中对齐）
        label_size = self.size()
        pixmap_size = self.pixmap.size()
        print(f"Label size: {label_size}, Pixmap size: {pixmap_size}")

        if pixmap_size.width() == 0 or pixmap_size.height() == 0:
            print("Invalid pixmap size, returning empty QRect（无效的图片尺寸，返回空矩形）")
            return QRect()

        # 计算缩放比例，保持宽高比
        scale = min(label_size.width() / pixmap_size.width(),
                    label_size.height() / pixmap_size.height())
        print(f"Scale factor: {scale}")

        # 计算绘制后的图像尺寸
        scaled_width = int(pixmap_size.width() * scale)
        scaled_height = int(pixmap_size.height() * scale)
        print(f"Scaled size: {scaled_width}x{scaled_height}")

        # 计算居中位置
        x = (label_size.width() - scaled_width) // 2
        y = (label_size.height() - scaled_height) // 2
        print(f"Scaled pixmap rect: ({x}, {y}, {scaled_width}, {scaled_height})")

        return QRect(x, y, scaled_width, scaled_height)

    def get_scaled_selection_rect(self):
        """获取选区在缩放图片上的实际区域"""
        print("get_scaled_selection_rect called")
        if not self.pixmap or self.selection_rect.isNull():
            print("No pixmap or selection rect is null, returning empty QRect")
            return QRect()
            
        # 获取图片的绘制区域
        pixmap_rect = self.get_scaled_pixmap_rect()
        original_pixmap_size = self.pixmap.size()
        print(f"Pixmap rect: {pixmap_rect}, Original pixmap size: {original_pixmap_size}")
        
        # 如果原始图片尺寸无效，返回空矩形
        if original_pixmap_size.width() == 0 or original_pixmap_size.height() == 0:
            print("Invalid original pixmap size, returning empty QRect")
            return QRect()
            
        # 计算缩放比例
        scale_x = pixmap_rect.width() / original_pixmap_size.width()
        scale_y = pixmap_rect.height() / original_pixmap_size.height()
        print(f"Scale factors - X: {scale_x}, Y: {scale_y}")
        
        # 计算选区在绘制图片上的位置
        scaled_x = int(self.selection_rect.x() * scale_x) + pixmap_rect.x()
        scaled_y = int(self.selection_rect.y() * scale_y) + pixmap_rect.y()
        scaled_width = int(self.selection_rect.width() * scale_x)
        scaled_height = int(self.selection_rect.height() * scale_y)
        print(f"Scaled selection rect: ({scaled_x}, {scaled_y}, {scaled_width}, {scaled_height})")
        
        return QRect(scaled_x, scaled_y, scaled_width, scaled_height)

    def setPixmap(self, pixmap):
        """设置图片并调整标签大小以适应图片尺寸"""
        print("setPixmap called（设置图片）")
        self.pixmap = pixmap
        # 不调用父类的setPixmap方法，避免影响布局
        # super().setPixmap(pixmap)
        self.update()
        
        # 发送图片尺寸信号
        if pixmap and not pixmap.isNull():
            try:
                print(f"Emitting imageLoaded signal with width: {pixmap.width()}, height: {pixmap.height()}")
                self.imageLoaded.emit(pixmap.width(), pixmap.height())
                print("imageLoaded signal emitted successfully")
            except Exception as e:
                print(f"Error emitting imageLoaded signal: {e}")
                import traceback
                traceback.print_exc()

    def mouseMoveEvent(self, event: QMouseEvent):
        """处理鼠标移动事件"""
        if self.drawing and self.pixmap:
            print(f"mouseMoveEvent called, position: {event.pos()} （处理鼠标移动事件，正在绘制选区）")
            self.end_point = event.pos()
            self.update()
        # 调用父类方法确保事件被正确处理
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event: QMouseEvent):
        """处理鼠标释放事件"""
        print(f"mouseReleaseEvent called, button: {event.button()}")
        if self.drawing and event.button() == Qt.MouseButton.LeftButton:
            print("Processing mouse release for drawing")
            self.drawing = False
            self.end_point = event.pos()
            self.update()
            
            # 创建选区并确保其有效性
            new_selection = QRect(self.start_point, self.end_point).normalized()
            print(f"New selection: {new_selection}")
            
            # 检查选区是否有效
            if new_selection.width() > 0 and new_selection.height() > 0:
                print("Valid selection, converting coordinates")
                # 转换选区坐标到原始图片坐标
                self.selection_rect = self.convert_selection_to_original(new_selection)
                print(f"Converted selection rect: {self.selection_rect}")
                
                # 发射选区改变信号
                print("Emitting selection changed signal")
                self.emit_selection_changed()
                print("Selection changed signal emitted")
            else:
                # 如果新选区无效，清除当前选区
                print("Invalid selection, clearing selection rect")
                self.selection_rect = QRect()
                self.update()
        
        # 接受事件以确保后续事件正常工作
        event.accept()
        
        # 调用父类方法确保事件被正确处理
        super().mouseReleaseEvent(event)

    def convert_selection_to_original(self, selection_rect):
        """将选区坐标转换为原始图片坐标"""
        print(f"convert_selection_to_original called with rect: {selection_rect}")
        if not self.pixmap:
            print("No pixmap, returning original rect")
            return selection_rect
            
        # 获取图片的绘制区域
        pixmap_rect = self.get_scaled_pixmap_rect()
        original_pixmap_size = self.pixmap.size()
        print(f"Pixmap rect: {pixmap_rect}, Original pixmap size: {original_pixmap_size}")
        
        # 计算缩放比例
        if pixmap_rect.width() == 0 or pixmap_rect.height() == 0:
            print("Invalid pixmap rect, returning empty QRect")
            return QRect()
            
        scale_x = original_pixmap_size.width() / pixmap_rect.width()
        scale_y = original_pixmap_size.height() / pixmap_rect.height()
        print(f"Scale factors - X: {scale_x}, Y: {scale_y}")
        
        # 转换选区坐标到原始图片坐标
        print(f"Selection rect coordinates - X: {selection_rect.x()}, Y: {selection_rect.y()}")
        print(f"Pixmap rect offset - X: {pixmap_rect.x()}, Y: {pixmap_rect.y()}")
        adjusted_x = selection_rect.x() - pixmap_rect.x()
        adjusted_y = selection_rect.y() - pixmap_rect.y()
        print(f"Adjusted coordinates - X: {adjusted_x}, Y: {adjusted_y}")
        
        original_x = int(adjusted_x * scale_x)
        original_y = int(adjusted_y * scale_y)
        original_width = int(selection_rect.width() * scale_x)
        original_height = int(selection_rect.height() * scale_y)
        print(f"Original coordinates - X: {original_x}, Y: {original_y}, Width: {original_width}, Height: {original_height}")
        
        # 确保选区不超出图片边界
        original_x = max(0, original_x)
        original_y = max(0, original_y)
        original_width = min(original_pixmap_size.width() - original_x, original_width)
        original_height = min(original_pixmap_size.height() - original_y, original_height)
        print(f"Clamped coordinates - X: {original_x}, Y: {original_y}, Width: {original_width}, Height: {original_height}")
        
        result = QRect(original_x, original_y, original_width, original_height)
        print(f"Converted selection rect: {result}")
        return result

    def emit_selection_changed(self):
        """发射选区改变信号"""
        print("emit_selection_changed called（发射选区改变信号）")
        if self.pixmap and not self.selection_rect.isNull():
            try:
                print(f"Emitting signal with selection rect: {self.selection_rect}")
                # 获取选区在原始图片中的尺寸和坐标
                x = self.selection_rect.x()
                y = self.selection_rect.y()
                width = self.selection_rect.width()
                height = self.selection_rect.height()
                print(f"Selection details - X: {x}, Y: {y}, Width: {width}, Height: {height}")
                
                # 截取选区图像
                print("Copying pixmap（复制图片）")
                cropped_pixmap = self.pixmap.copy(self.selection_rect)
                print("Pixmap copied successfully（图片复制成功）")
                
                # 生成recordPos（这里只是一个示例格式）
                record_pos = f"[{x},{y},{x+width},{y+height}]"
                print(f"Record pos: {record_pos}")
                
                # 生成名称（示例）
                name = "screenshot"
                print(f"Name: {name}")
                
                # 发射信号
                print("Emitting signal（发射信号）")
                # 移除对receivers方法的调用，该方法在PyQt6中不可用
                self.selectionChanged.emit(cropped_pixmap, width, height, x, y, record_pos, name)
                print("Signal emitted successfully（信号发射成功）")
            except Exception as e:
                # 出现异常时不中断程序
                print(f"Error in emit_selection_changed: {e}")
                traceback.print_exc()
        else:
            print("Pixmap is null or selection rect is null, skipping signal emission（图片为空或选区为空，跳过信号发射）")

    def paintEvent(self, event):
        """绘制图片和选区"""
        super().paintEvent(event)
        
        # 创建一个QPainter实例用于所有绘制操作
        painter = QPainter(self)
        
        # 绘制图片
        if self.pixmap and not self.pixmap.isNull():
            draw_rect = self.get_scaled_pixmap_rect()
            painter.drawPixmap(draw_rect, self.pixmap)
        
        # 绘制正在绘制的选框（红色）
        if self.drawing and self.pixmap and not self.pixmap.isNull():
            selection_rect = QRect(self.start_point, self.end_point).normalized()
            # 只有当选区有实际大小时才绘制，避免绘制大小为0的矩形导致访问违规
            if selection_rect.width() >= 1 and selection_rect.height() >= 1:
                painter.setPen(QPen(QColor(255, 0, 0), 2, Qt.PenStyle.DashLine))
                painter.drawRect(selection_rect)
        
        # 绘制已确认的选框（绿色）
        elif self.pixmap and not self.pixmap.isNull() and not self.selection_rect.isNull():
            try:
                scaled_selection = self.get_scaled_selection_rect()
                if not scaled_selection.isNull() and scaled_selection.width() > 0 and scaled_selection.height() > 0:
                    painter.setPen(QPen(QColor(0, 255, 0), 2, Qt.PenStyle.DashLine))
                    painter.drawRect(scaled_selection)
            except Exception as e:
                print(f"Error drawing confirmed selection: {e}")
                traceback.print_exc()

    def dragEnterEvent(self, event: QDragEnterEvent):
        """处理拖拽进入事件"""
        print("dragEnterEvent called")

        # 检查拖拽的数据是否包含图片文件
        if event.mimeData().hasUrls():
            urls = event.mimeData().urls()
            if urls:
                file_path = urls[0].toLocalFile()
                if os.path.isfile(file_path):
                    # 检查文件扩展名是否为支持的图片格式
                    ext = os.path.splitext(file_path)[1].lower()
                    if ext in ['.png', '.jpg', '.jpeg', '.bmp']:
                        print(f"Accepting drag for file: {file_path}")
                        event.acceptProposedAction()
                        return
        print("Ignoring drag event")
        event.ignore()

    def dropEvent(self, event: QDropEvent):
        """处理拖拽释放事件"""
        print("dropEvent called （处理拖拽释放事件）")

        if event.mimeData().hasUrls():
            urls = event.mimeData().urls()
            if urls:
                file_path = urls[0].toLocalFile()
                if os.path.isfile(file_path):
                    # 检查文件扩展名是否为支持的图片格式
                    ext = os.path.splitext(file_path)[1].lower()
                    if ext in ['.png', '.jpg', '.jpeg', '.bmp']:
                        print(f"Loading dropped image: {file_path}")
                        # 加载图片
                        self.load_image_from_path(file_path)
                        event.acceptProposedAction()
                        return
        print("Ignoring drop event")
        event.ignore()